#include "widget.h"
#include "ui_widget.h"
#include <QTime>
#include <QDebug>
extern "C"{
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
}
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
}

Widget::~Widget()
{
    delete ui;
}

void Delay(int msec){
    QTime dieTime = QTime::currentTime().addMSecs(msec);
    while(QTime::currentTime() < dieTime)
        QCoreApplication::processEvents(QEventLoop::AllEvents,100);
}



void Widget::on_pushButton_clicked()
{
    AVFormatContext *pFormatCtx;
    int i,videoindex;
    AVCodecContext *pCodecCtx;
    AVCodec *pCodec;
    AVFrame *pFrame , *pFrameRGB;
    unsigned char *out_buffer;
    AVPacket *packet;

    int ret,got_picture;
    struct SwsContext *img_convert_ctx;

    char filepath[] = "rtsp地址";
    // 初始化编解码库
    av_register_all(); // 创建AVFormatContext对象，与码流相关的结构
    pFormatCtx = avformat_alloc_context();
    // 初始化pFormatCtx结构
    if (avformat_open_input(&pFormatCtx, filepath, NULL, NULL) != 0){
        qDebug() << "Couldn't open input stream. . " << endl;
        return;
    }
    // 获取音频视频流数据信息
    if(avformat_find_stream_info(pFormatCtx,NULL)<0){
        qDebug() << "Couldn't find stream information. " << endl;
        return;
    }
    videoindex = -1;
    // nb_streams视音频流的个数，这里当查找到视频流时就中断了。
    for(int i=0;i<pFormatCtx->nb_streams;i++){
        if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){
            videoindex=i;
            break;
        }
    }
    if(videoindex==-1){
        qDebug() << "Didn't find a video stream. " << endl;
        return;
    }
    // 获取视频流编码结构
    pCodecCtx = pFormatCtx->streams[videoindex]->codec;
    // 查找解码器
    pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
    if(pCodec==NULL){
        qDebug() << "codec not found." << endl;
        return;
    }
    // 用于初始化pCodecCtx结构
    if(avcodec_open2(pCodecCtx,pCodec,NULL)<0){
        qDebug() << "Could not open codec. " << endl;
        return;
    }
    // 创建帧结构，此函数仅分配基本结构空间，图像数据空间需通过av_malloc分配 。
    pFrame = av_frame_alloc();
    pFrameRGB = av_frame_alloc();
    // 创建动态内存，创建存储图像数据的空间
    // av_image_get_buffer_size 获取一帧图像需要的大小
    out_buffer = (unsigned char*)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_RGB32, pCodecCtx->width, pCodecCtx->height,1));
    av_image_fill_arrays(pFrameRGB->data,pFrameRGB->linesize,out_buffer,
                         AV_PIX_FMT_RGB32, pCodecCtx->width,pCodecCtx->height, 1);
    packet = (AVPacket*)av_malloc(sizeof(AVPacket));
    // Output Info
    qDebug() << "------------ File Information -------------" << endl;
    // 此函数打印输入或输出的详细信息
    av_dump_format(pFormatCtx, 0, filepath, 0);
    qDebug() << "----------------" << endl;
    // 初始化img_convert_ctx结构
    img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,pCodecCtx->pix_fmt,
                                     pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_RGB32, SWS_BICUBIC, NULL, NULL, NULL);
    // av_read_frame读取一帧未解码的数据
    while(av_read_frame(pFormatCtx,packet)>=0){
        // 如果是视频数据
        if (packet->stream_index==videoindex){
            // 解码一帧视频数据
            ret = avcodec_decode_video2(pCodecCtx,pFrame, &got_picture, packet);
            if(ret<0){
                qDebug() << "Decode error" << endl;
                return;
            }
            if(got_picture){
                /**
                 * @brief sws_scale
                 * FFmpeg中的 sws_scale() 函数主要是用来做视频像素格式和分辨率的转换，
                 * 其优势  ：可以在同一个函数里实现：1.图像色彩空间转换， 2:分辨率缩放，3:前后图像滤波处理。
                 * 不足之处：效率相对较低，不如libyuv或shader
                 */
                sws_scale(img_convert_ctx, (const unsigned char* const*)pFrame->data,  pFrame->linesize, 0, pCodecCtx->height,
                          pFrameRGB->data, pFrameRGB->linesize);
                QImage img((uchar*)pFrameRGB->data[0],pCodecCtx->width,pCodecCtx->height, QImage::Format_RGB32);
                ui->label->setPixmap(QPixmap::fromImage(img));
                Delay(40); // 控制播放速度
            }
        }
        av_free_packet(packet);
    }
    //  释放sws_scale
    sws_freeContext(img_convert_ctx);
    av_frame_free(&pFrameRGB);
    av_frame_free(&pFrame);
    avcodec_close(pCodecCtx);
    avformat_close_input(&pFormatCtx);

}
